package com.sun.javafx.fxml;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 简单对象包装类
 */
public class POJOAdapter {

    protected static final ConcurrentHashMap<Class<?>, MethodCache> cache = new ConcurrentHashMap<>();

    static class MethodCache {
        Map<String,Method> getCache = new HashMap<>();
        Map<String,Method> setCache = new HashMap<>();

        MethodCache(Class<?> type){
            for (Method method : type.getMethods()) {
                String name = method.getName();
                if(isGet(name)){
                    getCache.put(lowerFirst(name.substring(3)),method);
                }else if(isSet(name)){
                    setCache.put(lowerFirst(name.substring(3)),method);
                }
            }
        }

        private boolean isSet(String name) {
            return name.charAt(0) == 's' && name.charAt(1) == 'e' && name.charAt(2) == 't';
        }

        private boolean isGet(String name) {
            return name.charAt(0) == 'g' && name.charAt(1) == 'e' && name.charAt(2) == 't';
        }

        public Method getMethod(String flied) {
            return getCache.get(flied);
        }

        public Method setMethod(String flied) {
            return setCache.get(flied);
        }
    }

    final Object target;
    final Class<?> type;

    public Object getTarget() {
        return target;
    }

    public Class<?> getType() {
        return type;
    }

    public POJOAdapter(Object target) {
        this.target = target;
        this.type = target.getClass();
    }

    /**
     * 设置属性
     *
     * 调用公开的set方法设置属性
     * @param flied 字段名
     * @param value 值
     */
    public void set(String flied,Object value){
        Method setMethod = findSetMethod(flied);
        try {
            setMethod.invoke(target,value);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    private Method findGetMethod(String flied) {
        MethodCache methodCache = getInner();
        Method method = methodCache.getMethod(flied);
        if(method == null){
            throw new RuntimeException("没有找到公开的get方法 flied=" + flied);
        }
        return method;
    }

    private Method findSetMethod(String flied) {
        MethodCache methodCache = getInner();
        Method method = methodCache.setMethod(flied);
        if(method == null){
            throw new RuntimeException("没有找到公开的set方法 flied=" + flied);
        }
        return method;
    }

    private MethodCache getInner() {
        MethodCache methodCache = cache.get(type);
        if(methodCache == null){
            methodCache = initInner();
        }
        return methodCache;
    }

    private synchronized MethodCache initInner() {
        MethodCache methodCache = cache.get(type);
        if(methodCache == null){
            methodCache = new MethodCache(type);
            cache.put(type,methodCache);
        }
        return methodCache;
    }


    /**
     * 获取属性
     * @param flied 字段名
     * @return 值
     */
    public Object get(String flied){
        Method getMethod = findGetMethod(flied);
        try {
            return getMethod.invoke(target);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }



    private static String lowerFirst(String str) {
        // 同理
        char[] cs=str.toCharArray();
        cs[0]+=32;
        return String.valueOf(cs);
    }
}
